<?php

namespace Cframe;

class Cache
{
    private static $cache_floder = '';
    private static $cache_type = array();
    private static $cache_save = array();
    private static $cache_save_file = array();

    private function run()
    {
        static::$cache_floder = RUNTIME_PATH . "Cache" . DS;
        static::setType(array(
            'Cache' => static::$cache_floder . 'Cache' . DS,
            'Tpl' => static::$cache_floder . 'Tpl' . DS,
            'Temp' => static::$cache_floder . 'Temp' . DS,
            'Hook' => static::$cache_floder . 'Hook' . DS,
            'Db' => static::$cache_floder . 'Data' . DS));
    }

    /**
     * @param $name
     * @param $value
     */
    private static function setType($name)
    {
        static::$cache_type = array_merge(static::$cache_type, $name);
    }

    /** 获取缓存
     * @param $name 缓存的名称
     * @return mixed|string 当有这个缓存文件时返回数组,没有则返回空
     */
    private function loadCache($name)
    {
        $path = explode('.', $name);
        $name2 = array_pop($path);
        $name2 = hash('md5', $name2);
        if (!isset(static::$cache_save[$name2])) {
            $file = static::file_name($name);
            if (file_exists($file)) {
                $data = unserialize(file_get_contents($file));
                static::$cache_save[$name] = $data;
                return $data;
            }
            return array();
        } else {
            return static::$cache_save[$name2];
        }
    }

    /** 获取或生成缓存文件的路径
     * @param $name 缓存的名称
     * @param bool $is_c 是否创建
     * @return string 返回完整路径
     * @throws \ErrorException 当没有名称例如,My只有type没有名称将会报错
     */
    private static function file_name($name, $is_c = false)
    {

        if (strstr($name, '.')) {
            $path = explode('.', $name);
            $name = array_pop($path);
            $last = $path;
            $path = array_shift($last);
            $last = empty($last) ? '' : implode(DS, $last) . DS;
        } else {
            $path = $name;
            $name = '';
        }
        $path = isset(static::$cache_type[$path]) ? static::$cache_type[$path] : '';
        if (empty($path)) {
            throw new CacheException("请输入正确的缓存类型");
        }
        $path = $path . $last;
        if ($is_c && !empty($path) && !file_exists($path) && !mkdir($path, 0777, true)) {
            throw new CacheException("创建文件夹失败，请检查目录是否可写");
        }
        if (empty($name)) {
            throw new CacheException("找不到相关缓存文件");
        }
        $name = hash('md5', $name);
        if (!isset(static::$cache_save_file[$name])) {
            $filename = $path . $name . '.php';
            static::$cache_save_file[$name] = $filename;
        } else {
            return static::$cache_save_file[$name];
        }
    }

    /** 设置缓存
     * @param $name 缓存的名称
     * @param $content 需要缓存的内容
     */
    private function setCache($name, $content)
    {
        $name = static::file_name($name, true);
        file_put_contents($name, serialize($content));
    }

    private function delCache($name, $is_f = false)
    {
        $path = explode('.', $name);
        $name2 = array_pop($path);
        $name2 = hash('md5', $name2);
        if (isset(static::$cache_save[$name])) {
            unset(static::$cache_save[$name]);
        }
        if ($is_f) {
            self::floder($name);
            return;
        }
        $file = static::file_name($name);
        if (file_exists($file)) {
            @unlink($file);
        }
    }

    private function floder($name)
    {
        $path = explode('.', $name);
        $name = array_pop($path);
        $last = $path;
        $path = array_shift($last);
        $last = empty($last) ? '' : implode(DS, $last) . DS;
        $path = isset(static::$cache_type[$path]) ? static::$cache_type[$path] : '';
        if (empty($path)) {
            throw new CacheException("请输入正确的缓存类型");
        }
        $path = $path . $last;
        self::deepScanDir($path);
    }

    private function deepScanDir($dir)
    {
        $fileArr = array();
        $dirArr = array();
        $dir = rtrim($dir, '\/');
        if (is_dir($dir)) {
            $dirHandle = opendir($dir);
            while (false !== ($fileName = readdir($dirHandle))) {
                $subFile = $dir . DIRECTORY_SEPARATOR . $fileName;
                if (is_file($subFile)) {
                    @unlink($subFile);
                } elseif (is_dir($subFile) && str_replace('.', '', $fileName) != '') {
                    $arr = self::deepScanDir($subFile);
                }
            }
            closedir($dirHandle);
        }
    }

    /** 清楚缓存
     * @param string $type 清处的自定类型的缓存
     */
    private function cleanCache($type = '')
    {
        $path = empty($type) ? static::$cache_floder : static::$cache_floder . DS . $type;
        $dir = opendir(rtrim($path, '\/'));
        while (false !== ($filname = readdir($dir))) {
            $filname = $path . DS . $filname;
            if (is_file($filname) && file_exists($filname)) {
                @unlink($filname);
            }
        }
    }

    public static function cache($func = '', $name = '', $value = '', $is_f = false)
    {
        switch (strtolower($func)) {
            case "set":
                self::setCache($name, $value);
                break;
            case "load":
                $value = self::loadCache($name);
                break;
            case "clean":
                self::cleanCache($name);
                break;
            case "del":
                self::delCache($name, $is_f);
                break;
        }
        if (isset($value)) {
            return $value;
        }
    }

    public static function __callStatic($name, $arguments)
    {
        self::run();
        array_unshift($arguments, $name);
        return call_user_func_array(array(__CLASS__, 'cache'), $arguments);
    }
}

class CacheException extends \RuntimeException
{

}